import json
import logging
import random
import re
import traceback
from datetime import datetime

from flask import request, make_response, abort, current_app, session
from flask.json import jsonify

from info import redis_store, constants, db
from info.lib.yuntongxun.sms import CCP
from info.models import User
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
from . import passport_blu


@passport_blu.route('/image_code')
def get_image_code():
    """
    获取图片验证码
    :return:
    """

    # 1. 获取到当前的图片编号id
    code_id = request.args.get('code_id')
    if not code_id:
        logging.error('没有传入code_id')
        abort(404)

    # 2. 生成验证码
    name, text, image = captcha.generate_captcha()
    try:
        # 保存当前生成的图片验证码内容
        redis_store.setex('ImageCode_' + code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        traceback.print_exc()
        logging.error(e)
        abort(500)

    # 返回响应内容
    response = make_response(image)
    # 设置内容类型
    response.headers['Content-Type'] = 'image/jpg'

    return response


@passport_blu.route('/register', methods=["POST", "GET"])
def register():
    """注册功能
    1 获取参数
    2 校验参数
    3 从redis获取真实的短信验证码 和发过来的对比
    4.如果一致 初始化User对象  添加到数据
    5.保存用户的登录状态
    6 返回相应

    """
    # 1获取参数
    param_dict = request.json
    mobile = param_dict.get('mobile')
    smscode = param_dict.get('smscode')
    password = param_dict.get('password')
    # 2校验参数
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不能为空')

    # 手机号的正则校验
    if not re.match(r'1[3456789]\d{9}', mobile):
        ret = {'errno': RET.PARAMERR, 'errmsg': '手机号格式不正确'}
        return jsonify(ret)

    # 3从redis获取真实的短信验证码和发过来的对比
    try:
        real_sms_code = redis_store.get('SMS_' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        traceback.print_exc()
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码过期')
    # 4.如果一致
    if real_sms_code != smscode:
        return jsonify(errno=RET.DATAERR, errmsg='验证码输入错误')

    # 初始化User对象添加到数据
    user = User()
    user.mobile = mobile
    # 刚注册没有昵称 默认和手机号一样
    user.nick_name = mobile
    # 最后一个登录时间
    user.last_login = datetime.now()
    # 密码  加密
    user.password = password

    try:
        db.session.add(user)
        db.session.commit()

        print('111111')
    except Exception as e:
        print('2222')
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据保存失败')

    print('user_id----%s' % user.id)
    # 5.保存用户的登录状态
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    # 6返回相应
    return jsonify(errno=RET.OK, errmsg='注册成功')


@passport_blu.route('/login', methods=["POST", "GET"])
def login():
    """登录功能
    1 获取参数
    2 校验参数
    3 逻辑
    4.保存登录状态
    6 返回相应

    """
    # 1获取参数
    param_dict = request.json
    mobile = param_dict.get('mobile')
    password = param_dict.get('password')

    # 2. 校验参数
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 校验手机号是否正确
    if not re.match('1[35678]\\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机号格式不正确")

    # 3. 校验密码是否正确
    # 先查询出当前是否有指定手机号的用户
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询错误")
    # 判断用户是否存在
    if not user:
        return jsonify(errno=RET.NODATA, errmsg="用户不存在")

    # 校验登录的密码和当前用户的密码是否一致
    if not user.check_password(password):
        return jsonify(errno=RET.PWDERR, errmsg="用户名或者密码错误")

    # 4. 保存用户的登录状态
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name

    # 设置当前用户最后一次登录的时间
    user.last_login = datetime.now()

    # 如果在视图函数中，对模型上的属性有修改，那么需要commit到数据库保存
    # 但是其实可以不用自己去写 db.session.commit(),前提是对SQLAlchemy有过相关配置SQLALCHEMY_COMMIT_ON_TEARDOWN

    # try:
    #     db.session.commit()
    # except Exception as e:
    #     db.session.rollback()
    #     current_app.logger.error(e)

    # 5返回相应
    return jsonify(errno=RET.OK, errmsg='注册成功')


@passport_blu.route("/logout", methods=['POST'])
def logout():
    """
    清除session中的对应登录之后保存的信息
    :return:
    """
    # pop返回 删除的值  如果不存在 就返回None
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    # 如果登录的是管理员　把管理员信息也清除
    session.pop('is_admin', None)

    # 返回结果
    return jsonify(errno=RET.OK, errmsg="OK")


@passport_blu.route('/smscode', methods=['POST', 'GET'])
def send_sms():
    """
    发送短信的逻辑
    1 获取参数：手机号 验证码 图片验证码的编号
    2校验  参数是否符合规则 判断是否为空
    3 从reids获取真是的验证码 和 接受的验证码对比

    4 对比如果不一致  返回错误信息
    5对比如果 一致  生成随机的短信 验证码
    6 发送短信， 验证码内容存到redis
    7返回相应 发送是否成功
    :return:

    """
    # 1获取参数：手机号推按验证码图片验证码的编号   form args   name=zhangsan&age=18
    # params_dict = json.loads(request.data)
    # request.json 获取的数据直接是转换好的字典
    # {“mobile”：“18121345678”,"image_code":'HSBD',“image_code_id":"fdjhfslkdjhgshdkljskjh"}
    params_dict = request.json
    mobile = params_dict.get('mobile')
    image_code = params_dict.get('image_code')
    image_code_id = params_dict.get('image_code_id')

    # 2校验  参数是否符合规则 判断是否为空
    if not all([mobile, image_code, image_code_id]):
        ret = {'errno': RET.PARAMERR, 'errmsg': '参数有误'}
        return jsonify(ret)
    # 手机号的正则校验
    if not re.match(r'1[3456789]\d{9}', mobile):
        ret = {'errno': RET.PARAMERR, 'errmsg': '手机号格式不正确'}
        return jsonify(ret)

    # 3 从reids获取真是的验证码 和 接受的验证码对比
    try:
        real_image_code = redis_store.get('ImageCode_' + image_code_id)
    except Exception as e:
        # logging.error(e)
        current_app.logger.error(e)
        ret = {'errno': RET.DBERR, 'errmsg': '数据查询失败'}
        return jsonify(ret)

    if not real_image_code:
        # 数据不存在 过期了
        ret = {'errno': RET.NODATA, 'errmsg': '图片验证码已过期'}
        return jsonify(ret)

    # 4 对比如果不一致  返回错误信息
    if real_image_code.upper() != image_code.upper():
        ret = {'errno': RET.DATAERR, 'errmsg': '验证码输入错误'}
        return jsonify(ret)

    # 5对比如果 一致  生成随机的短信 验证码
    sms_code_str = "%06d" % random.randint(0, 999999)
    current_app.logger.error('短信验证码是:::%s' % sms_code_str)

    # 6发送短信， 验证码内容存到redis
    # ccp = CCP()
    # # 注意： 测试的短信模板编号为1   12345是验证码 5是5分钟
    # result = ccp.send_template_sms(mobile, [sms_code_str, constants.SMS_CODE_REDIS_EXPIRES
    #                                         ], 1)
    # if result != 0:
    #     ret = {'errno': RET.THIRDERR, 'errmsg': '发送短信失败，稍后再试'}
    #     return jsonify(ret)

    # 验证码内容存到redis
    try:
        redis_store.set('SMS_' + mobile, sms_code_str, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        ret = {'errno': RET.DBERR, 'errmsg': '数据保存失败'}
        return jsonify(ret)

    # 7返回相应 发送是否成功
    ret = {'errno': RET.OK, 'errmsg': '发送成功'}
    print('发送成功')
    return jsonify(ret)
